home *** CD-ROM | disk | FTP | other *** search
/ Scene Storm / Scene Storm - Volume 1.iso / coding / c / cc / cc.c < prev    next >
C/C++ Source or Header  |  1995-11-14  |  20KB  |  985 lines

  1. /**
  2. ***  cc.c   Unix compatible frontend for Amiga's C compilers
  3. ***
  4. ***  This program is free software; you can redistribute it and/or modify
  5. ***  it under the terms of the GNU General Public License as published by
  6. ***  the Free Software Foundation; either version 2 of the License, or
  7. ***  (at your option) any later version.
  8. ***
  9. ***  This program is distributed in the hope that it will be useful,
  10. ***  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ***  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. ***  GNU General Public License for more details.
  13. ***
  14. ***  You should have received a copy of the GNU General Public License
  15. ***  along with this program; if not, write to the Free Software
  16. ***  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. ***
  18. ***
  19. ***  Compiler:    dcc V3.01
  20. ***
  21. ***  Computer:    Amiga 1200
  22. ***
  23. ***  Author:    Jochen Wiedmann
  24. ***        Am Eisteich 9
  25. ***        72555 Metzingen
  26. ***        Germany
  27. ***
  28. ***        Phone: (49)7123 / 14881
  29. ***        Internet: wiedmann@zdv.uni-tuebingen.de
  30. ***
  31. ***
  32. ***
  33. ***  This is a Unix compatible frontend for gcc, SAS/C and Dice. In fact,
  34. ***  it does nothing than else than calling the appropriate frontends
  35. ***  with the appropriate options.
  36. ***
  37. ***  Supported options are:
  38. ***
  39. ***    -v        Verbose (try it :-)
  40. ***    -c        Don't link
  41. ***    -a        Compile only, don't assemble
  42. ***    -E        Run preprocessor only
  43. ***    -I<dir>     Look for include files in directory <dir>
  44. ***    -L<dir>     Look for libraries in directory <dir>
  45. ***    -o<file>    Set the name of the created file; it is recommended
  46. ***            to use this as the respective frontends might behave
  47. ***            different in selecting default names.
  48. ***    -D<symbol>  Defines preprocessor symbol; use -Dsymbol=var for
  49. ***            specific values.
  50. ***    -U<symbol>  Undefine the preprocessor symbol <symbol>.
  51. ***    -l<lib>     Link with library <lib>.
  52. ***    -g        Turn debugging on.
  53. ***    -O        Optimize
  54. ***
  55. **/
  56.  
  57. /**
  58. ***  Version string
  59. **/
  60. #define VERSION        1
  61. #define REVISION     1
  62. #define DATE    "11.10.94"
  63. #define VERS    "cc 1.1"
  64. #define VSTRING "cc 1.1 (11.10.94)"
  65. #define VERSTAG "\0$VER: cc 1.1 (11.10.94)"
  66. char Version[] = VSTRING;
  67.  
  68. char AmigaVersion[] = VERSTAG;
  69.  
  70.  
  71.  
  72.  
  73. /**
  74. ***  Include files
  75. **/
  76. #include <stdlib.h>
  77. #include <string.h>
  78. #include <stdio.h>
  79. #include <stdarg.h>
  80. #include <exec/lists.h>
  81. #include <exec/nodes.h>
  82. #include <clib/alib_protos.h>
  83. #include <clib/exec_protos.h>
  84. #include <clib/dos_protos.h>
  85. #include <pragmas/exec_pragmas.h>
  86. #include <pragmas/dos_pragmas.h>
  87. extern struct Library *SysBase;
  88. extern struct Library *DOSBase;
  89.  
  90.  
  91.  
  92.  
  93.  
  94. /**
  95. ***  List of options processed by cc:
  96. **/
  97. typedef enum
  98.   {
  99.     OPTION_UNKNOWN,
  100.     OPTION_VERBOSE,
  101.     OPTION_DEFINE,
  102.     OPTION_UNDEFINE,
  103.     OPTION_PREPROCESSOR_ONLY,
  104.     OPTION_ASSEMBLER_ONLY,
  105.     OPTION_NOLINK,
  106.     OPTION_INCLUDEDIR,
  107.     OPTION_LINKDIR,
  108.     OPTION_OPTIMIZE,
  109.     OPTION_DEBUGGING,
  110.     OPTION_LIBRARY,
  111.     OPTION_OUTPUT
  112.   } CompilerOption;
  113.  
  114.  
  115.  
  116.  
  117.  
  118. /**
  119. ***  This structure defines an element in the list of options.
  120. **/
  121. typedef struct
  122.   {
  123.     struct MinNode mn;
  124.     CompilerOption Option;
  125.     char *Arg;
  126.   } CurrentOption;
  127.  
  128.  
  129.  
  130.  
  131.  
  132. /**
  133. ***  Compatibility mode (Default: gcc)
  134. **/
  135. enum
  136.   {
  137.     COMPATIBILITYMODE_GCC,
  138.     COMPATIBILITYMODE_SAS,
  139.     COMPATIBILITYMODE_DICE,
  140.   } CompatibilityMode = COMPATIBILITYMODE_SAS;
  141. char *CompatibilityModeNames[] =
  142.   {
  143.     "-gcc",
  144.     "-sas",
  145.     "-dice"
  146.   };
  147.  
  148.  
  149.  
  150.  
  151. /**
  152. ***  Compiler mode (Default: Everything)
  153. **/
  154. enum
  155.   {
  156.     COMPILERMODE_PREPROCESSOR_ONLY,
  157.     COMPILERMODE_COMPILER_ONLY,
  158.     COMPILERMODE_ASSEMBLER_ONLY,
  159.     COMPILERMODE_EVERYTHING,
  160.   } CompilerMode = COMPILERMODE_EVERYTHING;
  161. char *CompilerModeNames[] =
  162.   {
  163.     "-E",
  164.     "-a",
  165.     "-c"
  166.   };
  167.  
  168.  
  169.  
  170.  
  171. /**
  172. ***  These lists are used to hold the current options.
  173. **/
  174. struct List OptionList;
  175.  
  176.  
  177.  
  178.  
  179.  
  180. /**
  181. ***  Guess, what this function does? :-)
  182. **/
  183. void Usage(void)
  184.  
  185.   {
  186.     printf("%s%s%s", "Usage: cc [options] [files]\n\
  187. \n\
  188. Options known to cc are:\n\
  189. \n\
  190. -v\t\tbe verbose\n\
  191. -o<file>\t\tsend output to <file> (usage is recommended)\n\
  192. -E\t\trun preprocessor only\n\
  193. -a\t\trun preprocessor and compiler only\n\
  194. -c\t\trun preprocessor, compiler and assembler, don't link\n\
  195. -I<dir>\t\tlook for include files in <dir>\n\
  196. -L<dir>\t\took for link libraries in <dir>\n\
  197. -l<lib>\t\tlink with library <lib>\n\
  198. -g\t\tturn debugging on\n\
  199. -O\t\tturn optimization on\n\
  200. -D<sym>\t\tdefine preprocessor symbol\n\
  201. -U<sym>\t\tundefine preprocessor symbol\n\
  202. -h,--help,?\tprint this message\n", Version, " UNIX 'cc' Front-End for SAS/C Compiler\n\n");
  203.     exit(5);
  204.   }
  205.  
  206.  
  207.  
  208.  
  209.  
  210. /**
  211. ***  This functions adds a new option to the list of options.
  212. **/
  213. void AddOption(CompilerOption co, char *arg)
  214.  
  215.   {
  216.     CurrentOption *cu;
  217.  
  218.     if (!(cu = malloc(sizeof(*cu))))
  219.       {
  220.     fprintf(stderr, "Out of memory!");
  221.     exit(20);
  222.       }
  223.     cu->Option = co;
  224.     cu->Arg = arg;
  225.     AddTail(&OptionList, (struct Node *) cu);
  226.   }
  227.  
  228.  
  229.  
  230.  
  231.  
  232. /**
  233. ***  This function handles options which may be splitted into two
  234. ***  arguments or not, like -I <dir> or -I<dir>.
  235. **/
  236. void AddOptionArg(CompilerOption co,
  237.           int *i,
  238.           int argc,
  239.           char *argv[])
  240.  
  241.   {
  242.     char *arg = &argv[*i][2];
  243.  
  244.     if (!*arg)
  245.       {
  246.     if (++(*i) >= argc)
  247.       {
  248.         fprintf(stderr, "%s: Missing argument: %s\n", argv[--(*i)]);
  249.         exit(20);
  250.       }
  251.     arg = argv[*i];
  252.       }
  253.  
  254.     AddOption(co, arg);
  255.   }
  256.  
  257.  
  258.  
  259.  
  260.  
  261. /**
  262. ***  This function is used to set the compatibility mode.
  263. **/
  264. void SetCompatibilityMode(int mode, int *set)
  265.  
  266.   {
  267.     if (*set)
  268.       {
  269.     fprintf(stderr, "cc, warning: %s overwrites %s\n",
  270.         CompatibilityModeNames[mode],
  271.         CompatibilityModeNames[CompatibilityMode]);
  272.     exit(10);
  273.       }
  274.     *set = TRUE;
  275.     CompatibilityMode = mode;
  276.   }
  277.  
  278.  
  279.  
  280.  
  281.  
  282. /**
  283. ***  This function is used to set the compatibility mode.
  284. **/
  285. void SetCompilerMode(int mode, int *set)
  286.  
  287.   {
  288.     if (*set)
  289.       {
  290.     fprintf(stderr, "cc warning: %s overwrites %s\n",
  291.         CompilerModeNames[mode],
  292.         CompilerModeNames[CompilerMode]);
  293.     exit(10);
  294.       }
  295.     *set = TRUE;
  296.     CompilerMode = mode;
  297.   }
  298.  
  299.  
  300.  
  301.  
  302.  
  303. /**
  304. ***  This function is used to build the string that is used to call
  305. ***  the real frontend. It supports strings of any length, thus it
  306. ***  may look somewhat complicated.
  307. **/
  308. void AddToString(char **strptr, char *format, ...)
  309.  
  310.   {
  311.     static char buffer[1024];    /*  Maximal length of *one* argument    */
  312.     static int RealLen;
  313.     static int MaxLen;
  314.     int len;
  315.     va_list args;
  316.  
  317.     va_start(args, format);
  318.     vsprintf(buffer, format, args);
  319.     len = strlen(buffer);
  320.  
  321.     if (!*strptr)
  322.       {
  323.     MaxLen = 0;
  324.       }
  325.  
  326.     if (len + RealLen + 1 > MaxLen)
  327.       {
  328.     /**
  329.     ***  Current buffer not sufficient, allocate a new buffer
  330.     **/
  331.     char *newstr;
  332.  
  333.     if (!(newstr = malloc(MaxLen+1024)))
  334.       {
  335.         fprintf(stderr, "Out of memory!");
  336.         exit(20);
  337.       }
  338.     MaxLen += 1024;
  339.  
  340.     if (*strptr)
  341.       {
  342.         strcpy(newstr, *strptr);
  343.       }
  344.     else
  345.       {
  346.         *newstr = '\0';
  347.         RealLen = 0;
  348.       }
  349.     *strptr = newstr;
  350.       }
  351.  
  352.     strcpy(*strptr + RealLen, buffer);
  353.     RealLen += len;
  354.   }
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361. /**
  362. ***  This function is used to parse the arguments. Options will
  363. ***  be included into OptionList, files in FileList.
  364. **/
  365. void ParseArgs(int argc,
  366.            char *argv[])
  367.  
  368.   {
  369.     int i;
  370.     /**
  371.     ***  These variables are used for checking if arguments repeat.
  372.     ***  Note that we keep them local: This allows, for example,
  373.     ***  to use different settings in the environment and on the
  374.     ***  command line.
  375.     **/
  376.     int CompatibilityModeIsSet = FALSE;
  377.     int CompilerModeIsSet = FALSE;
  378.  
  379.     for (i = 0;  i < argc;  i++)
  380.       {
  381.     char *argvi = argv[i];
  382.  
  383.     if (argvi[0] == '-')
  384.       {
  385.         /**
  386.         ***  Assume this to be a compiler option.
  387.         **/
  388.  
  389.         switch(argvi[1])
  390.           {
  391.         case '-':
  392.           if (strcmp(argvi, "--help") == 0)
  393.             {
  394.               Usage();
  395.             }
  396.           AddOption(OPTION_UNKNOWN, argvi);
  397.           break;
  398.         case 'D':
  399.           AddOptionArg(OPTION_DEFINE, &i, argc, argv);
  400.           break;
  401.         case 'E':
  402.           switch(argvi[2])
  403.             {
  404.               case '\0':
  405.             SetCompilerMode(COMPILERMODE_PREPROCESSOR_ONLY,
  406.                     &CompilerModeIsSet);
  407.             break;
  408.               default:
  409.             AddOption(OPTION_UNKNOWN, argvi);
  410.             break;
  411.             }
  412.           break;
  413.         case 'I':
  414.           AddOptionArg(OPTION_INCLUDEDIR, &i, argc, argv);
  415.           break;
  416.         case 'L':
  417.           AddOptionArg(OPTION_LINKDIR, &i, argc, argv);
  418.           break;
  419.         case 'O':
  420.           AddOption(OPTION_OPTIMIZE, &argvi[2]);
  421.           break;
  422.         case 'U':
  423.           AddOptionArg(OPTION_UNDEFINE, &i, argc, argv);
  424.           break;
  425.         case 'a':
  426.           switch(argvi[2])
  427.             {
  428.               case '\0':
  429.             SetCompilerMode(COMPILERMODE_COMPILER_ONLY,
  430.                     &CompilerModeIsSet);
  431.             break;
  432.               default:
  433.             AddOption(OPTION_UNKNOWN, argvi);
  434.             break;
  435.             }
  436.           break;
  437.         case 'c':
  438.           switch(argvi[2])
  439.             {
  440.               case '\0':
  441.             SetCompilerMode(COMPILERMODE_ASSEMBLER_ONLY,
  442.                     &CompilerModeIsSet);
  443.             break;
  444.               default:
  445.             AddOption(OPTION_UNKNOWN, argvi);
  446.             break;
  447.             }
  448.           break;
  449.         case 'd':
  450.           if (strcmp(argvi,
  451.                  CompatibilityModeNames[COMPATIBILITYMODE_DICE]) == 0)
  452.             {
  453.               SetCompatibilityMode(COMPATIBILITYMODE_DICE,
  454.                        &CompatibilityModeIsSet);
  455.             }
  456.           else
  457.             {
  458.               AddOption(OPTION_UNKNOWN, argvi);
  459.             }
  460.           break;
  461.         case 'g':
  462.           switch(argvi[2])
  463.             {
  464.               case '\0':
  465.             AddOption(OPTION_DEBUGGING, argvi);
  466.             break;
  467.               default:
  468.             if (strcmp(argvi,
  469.                    CompatibilityModeNames[COMPATIBILITYMODE_GCC]) == 0)
  470.               {
  471.                 SetCompatibilityMode(COMPATIBILITYMODE_GCC,
  472.                          &CompatibilityModeIsSet);
  473.               }
  474.             else
  475.               {
  476.                 AddOption(OPTION_UNKNOWN, argvi);
  477.               }
  478.             break;
  479.             }
  480.           break;
  481.         case 'h':
  482.           switch(argvi[2])
  483.             {
  484.               case '\0':
  485.             Usage();
  486.               default:
  487.             AddOption(OPTION_UNKNOWN, argvi);
  488.             break;
  489.             }
  490.           break;
  491.         case 'l':
  492.           AddOptionArg(OPTION_LIBRARY, &i, argc, argv);
  493.           break;
  494.         case 'o':
  495.           AddOptionArg(OPTION_OUTPUT, &i, argc, argv);
  496.           break;
  497.         case 's':
  498.           if (strcmp(argvi,
  499.                  CompatibilityModeNames[COMPATIBILITYMODE_SAS]) == 0)
  500.             {
  501.               SetCompatibilityMode(COMPATIBILITYMODE_SAS,
  502.                        &CompatibilityModeIsSet);
  503.             }
  504.           else
  505.             {
  506.               AddOption(OPTION_UNKNOWN, argvi);
  507.             }
  508.           break;
  509.         case 'v':
  510.           switch(argvi[2])
  511.             {
  512.               case '\0':
  513.             AddOption(OPTION_VERBOSE, argvi);
  514.             break;
  515.               default:
  516.             AddOption(OPTION_UNKNOWN, argvi);
  517.             break;
  518.             }
  519.             break;
  520.         default:
  521.           AddOption(OPTION_UNKNOWN, argvi);
  522.           break;
  523.           }
  524.       }
  525.     else if (strcmp(argvi, "?") == 0)
  526.       {
  527.         Usage();
  528.       }
  529.     else
  530.       {
  531.         AddOption(OPTION_UNKNOWN, argvi);
  532.       }
  533.       }
  534.   }
  535.  
  536.  
  537.  
  538.  
  539.  
  540. /**
  541. ***  This function calls gcc as a frontend.
  542. **/
  543. int CompileGcc(void)
  544.  
  545.   {
  546.     CurrentOption *co;
  547.     char *CompileString = NULL;
  548.     int Verbose = FALSE;
  549.  
  550.     AddToString(&CompileString, "gcc");
  551.  
  552.     for (co = (CurrentOption *) OptionList.lh_Head;
  553.      co->mn.mln_Succ != NULL;
  554.      co = (CurrentOption *) co->mn.mln_Succ)
  555.       {
  556.     switch (co->Option)
  557.       {
  558.         case OPTION_UNKNOWN:
  559.           AddToString(&CompileString, " \"%s\"", co->Arg);
  560.           break;
  561.         case OPTION_VERBOSE:
  562.           AddToString(&CompileString, " -v");
  563.           Verbose = TRUE;
  564.           break;
  565.         case OPTION_DEFINE:
  566.           AddToString(&CompileString, " \"-D%s\"", co->Arg);
  567.           break;
  568.         case OPTION_UNDEFINE:
  569.           AddToString(&CompileString, " \"-U%s\"", co->Arg);
  570.           break;
  571.         case OPTION_PREPROCESSOR_ONLY:
  572.           AddToString(&CompileString, " -E");
  573.           break;
  574.         case OPTION_ASSEMBLER_ONLY:
  575.           AddToString(&CompileString, " -a");
  576.           break;
  577.         case OPTION_NOLINK:
  578.           AddToString(&CompileString, " -c");
  579.           break;
  580.         case OPTION_INCLUDEDIR:
  581.           AddToString(&CompileString, " \"-I%s\"", co->Arg);
  582.           break;
  583.         case OPTION_LINKDIR:
  584.           AddToString(&CompileString, " \"-L%s\"", co->Arg);
  585.           break;
  586.         case OPTION_OPTIMIZE:
  587.           AddToString(&CompileString, " \"-O%s\"", co->Arg);
  588.           break;
  589.         case OPTION_DEBUGGING:
  590.           AddToString(&CompileString, " -g");
  591.           break;
  592.         case OPTION_LIBRARY:
  593.           AddToString(&CompileString, " \"-l%s\"", co->Arg);
  594.           break;
  595.         case OPTION_OUTPUT:
  596.           AddToString(&CompileString, " -o \"%s\"", co->Arg);
  597.           break;
  598.       }
  599.       }
  600.  
  601.     AddToString(&CompileString, "\n");
  602.     if (Verbose)
  603.       {
  604.     printf("%s\n%s", Version, CompileString);
  605.       }
  606.  
  607.     return(system(CompileString));
  608.   }
  609.  
  610.  
  611.  
  612.  
  613.  
  614. /**
  615. ***  This function calls SAS/C as a frontend.
  616. **/
  617. int CompileSAS(void)
  618.  
  619.   {
  620.     CurrentOption *co;
  621.     char *CompileString = NULL;
  622.     int Verbose = FALSE;
  623.     char *OptionOutput = NULL;
  624.  
  625.     AddToString(&CompileString, "sc");
  626.  
  627.     for (co = (CurrentOption *) OptionList.lh_Head;
  628.      co->mn.mln_Succ != NULL;
  629.      co = (CurrentOption *) co->mn.mln_Succ)
  630.       {
  631.     switch (co->Option)
  632.       {
  633.         case OPTION_UNKNOWN:
  634.           AddToString(&CompileString, " \"%s\"", co->Arg);
  635.           break;
  636.         case OPTION_VERBOSE:
  637.           AddToString(&CompileString, " VERBOSE");
  638.           Verbose = TRUE;
  639.           break;
  640.         case OPTION_DEFINE:
  641.           AddToString(&CompileString, " DEF \"%s\"", co->Arg);
  642.           break;
  643.         case OPTION_UNDEFINE:    /*  Not supported   */
  644.           break;
  645.         case OPTION_INCLUDEDIR:
  646.           AddToString(&CompileString, " IDIR\"%s\"", co->Arg);
  647.           break;
  648.         case OPTION_LINKDIR:    /*  Not supported   */
  649.           break;
  650.         case OPTION_OPTIMIZE:
  651.           AddToString(&CompileString, " OPTIMIZE");
  652.           break;
  653.         case OPTION_DEBUGGING:
  654.           AddToString(&CompileString, " DEBUG FULLFLUSH");
  655.           break;
  656.         case OPTION_LIBRARY:
  657.           AddToString(&CompileString, " LIBRARY \"%s.lib\"", co->Arg);
  658.           break;
  659.         case OPTION_OUTPUT:
  660.           OptionOutput = co->Arg;
  661.           break;
  662.       }
  663.       }
  664.  
  665.     switch(CompilerMode)
  666.       {
  667.     case COMPILERMODE_PREPROCESSOR_ONLY:
  668.       AddToString(&CompileString, " PPONLY");
  669.     case COMPILERMODE_ASSEMBLER_ONLY:
  670.       if (OptionOutput)
  671.         {
  672.           AddToString(&CompileString, " OBJNAME \"%s\"", OptionOutput);
  673.         }
  674.       break;
  675.     case COMPILERMODE_COMPILER_ONLY:
  676.       if (!OptionOutput)
  677.         {
  678.           OptionOutput = "*";
  679.         }
  680.       AddToString(&CompileString, " \"DISASM=%s\"", OptionOutput);
  681.       break;
  682.     case COMPILERMODE_EVERYTHING:
  683.       if (OptionOutput)
  684.         {
  685.           AddToString(&CompileString, " PNAME \"%s\"", OptionOutput);
  686.         }
  687.       AddToString(&CompileString, " LINK");
  688.       break;
  689.       }
  690.  
  691.     AddToString(&CompileString, "\n");
  692.     if (Verbose)
  693.       {
  694.     printf("%s\n%s", Version, CompileString);
  695.       }
  696.  
  697.     return(system(CompileString));
  698.   }
  699.  
  700.  
  701.  
  702.  
  703.  
  704.  
  705. /**
  706. ***  This function calls Dice as a frontend.
  707. **/
  708. int CompileDice(void)
  709.  
  710.   {
  711.     CurrentOption *co;
  712.     char *CompileString = NULL;
  713.     int Verbose = FALSE;
  714.  
  715.     switch(CompilerMode)
  716.       {
  717.     case COMPILERMODE_PREPROCESSOR_ONLY:
  718.       AddToString(&CompileString, "dcpp");
  719.       break;
  720.     case COMPILERMODE_COMPILER_ONLY:
  721.       AddToString(&CompileString, "dcc -a");
  722.       break;
  723.     case COMPILERMODE_ASSEMBLER_ONLY:
  724.       AddToString(&CompileString, "dcc -c");
  725.       break;
  726.     default:
  727.       AddToString(&CompileString, "dcc");
  728.       break;
  729.       }
  730.  
  731.     for (co = (CurrentOption *) OptionList.lh_Head;
  732.      co->mn.mln_Succ != NULL;
  733.      co = (CurrentOption *) co->mn.mln_Succ)
  734.       {
  735.     switch (co->Option)
  736.       {
  737.         case OPTION_UNKNOWN:
  738.           AddToString(&CompileString, " \"%s\"", co->Arg);
  739.           break;
  740.         case OPTION_VERBOSE:
  741.           if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY)
  742.         {
  743.           AddToString(&CompileString, " -v", co->Arg);
  744.         }
  745.           Verbose = TRUE;
  746.           break;
  747.         case OPTION_DEFINE:
  748.           AddToString(&CompileString, " \"-D%s\"", co->Arg);
  749.           break;
  750.         case OPTION_UNDEFINE:        /*    Not supported    */
  751.           break;
  752.         case OPTION_INCLUDEDIR:
  753.           AddToString(&CompileString, " \"-I%s\"", co->Arg);
  754.           break;
  755.         case OPTION_LINKDIR:
  756.           if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY)
  757.         {
  758.           AddToString(&CompileString, " \"-L%s\"", co->Arg);
  759.         }
  760.           break;
  761.         case OPTION_OPTIMIZE:        /*    Not suported    */
  762.           break;
  763.         case OPTION_DEBUGGING:
  764.           if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY)
  765.         {
  766.           AddToString(&CompileString, " -s -d1");
  767.         }
  768.           break;
  769.         case OPTION_LIBRARY:
  770.           if (CompilerMode != COMPILERMODE_PREPROCESSOR_ONLY)
  771.         {
  772.           AddToString(&CompileString, " \"-l%s\"", co->Arg);
  773.         }
  774.           break;
  775.         case OPTION_OUTPUT:
  776.           AddToString(&CompileString, " -o \"%s\"", co->Arg);
  777.           break;
  778.       }
  779.       }
  780.  
  781.     AddToString(&CompileString, "\n");
  782.     if (Verbose)
  783.       {
  784.     printf("%s\n%s", Version, CompileString);
  785.       }
  786.  
  787.     return(system(CompileString));
  788.   }
  789.  
  790.  
  791.  
  792.  
  793.  
  794. /**
  795. ***  This function is used to split a string into arguments.
  796. ***  It returns an array similar to argv.
  797. ***
  798. ***  I don't like doing things for myself, but as far as I
  799. ***  can see neither SAS nor Dice offer a possibility of
  800. ***  doing this.
  801. ***
  802. ***  Inputs: argstr - the string to split into arguments,
  803. ***        for example an AmigaDOS command line;
  804. ***        may contain arguments like
  805. ***            "This is one argument"
  806. ***        or
  807. ***            "Note the "" inside this argument"
  808. ***        where the double quotation mark will be
  809. ***        changed into one.
  810. ***        argc - pointer to an int where to store the
  811. ***        number of arguments found in argstr
  812. ***
  813. ***  Result: an NULL terminated array of pointers to the
  814. ***        arguments or NULL; note that the pointers go
  815. ***        into argstr and argstr will be modified.
  816. **/
  817. char **SplitArgs(char *argstr, int *argcptr)
  818.  
  819.   {
  820.     int argc;
  821.     char *argptr;
  822.     char **argv;
  823.     char **argvptr;
  824.  
  825.     /**
  826.     ***  Parse the string for the first time counting
  827.     ***  the number of arguments.
  828.     **/
  829.     argptr = argstr;
  830.     argc = 0;
  831.     for(;;)
  832.       {
  833.     /**
  834.     ***  Skip blanks
  835.     **/
  836.     while (*argptr == ' '  ||  *argptr == '\t')
  837.       {
  838.         ++argptr;
  839.       }
  840.  
  841.     if (*argptr == '\0'  ||  *argptr == '\n'  ||  *argptr == '\r')
  842.       {
  843.         break;
  844.       }
  845.  
  846.     ++argc;
  847.  
  848.     if (*argptr == '\"')
  849.       {
  850.         do
  851.           {
  852.         ++argptr;
  853.         if (*argptr == '\"')
  854.           {
  855.             if (*(argptr+1) == '\"')
  856.               {
  857.             ++argptr;
  858.               }
  859.             else
  860.               {
  861.             break;
  862.               }
  863.           }
  864.           }
  865.         while (*argptr != '\0'  &&  *argptr != '\r'  &&  *argptr != '\n');
  866.       }
  867.     else
  868.       {
  869.         while (*argptr != '\0'  &&  *argptr != '\r'  &&  *argptr != '\n'  &&
  870.            *argptr != '\t'  &&  *argptr != ' ')
  871.           {
  872.         ++argptr;
  873.           }
  874.       }
  875.     {
  876.       char c;
  877.  
  878.       c = *argptr;
  879.       *(argptr++) = '\0';
  880.  
  881.       if (c == '\0'  ||  c == '\r'  ||  c == '\n')
  882.         {
  883.           break;
  884.         }
  885.     }
  886.       }
  887.  
  888.     *argcptr = argc;
  889.     if (!(argv = malloc(sizeof(char *) * (argc+1))))
  890.       {
  891.     return(NULL);
  892.       }
  893.  
  894.     /**
  895.     ***  Parse the string a second time
  896.     **/
  897.     for (argvptr = argv, argptr = argstr;  argc > 0;  --argc, ++argvptr)
  898.       {
  899.     int inside;
  900.  
  901.     while (*argptr == ' '  ||  *argptr == '\t')
  902.       {
  903.         ++argptr;
  904.       }
  905.  
  906.     if (*argptr == '\"')
  907.       {
  908.         ++argptr;
  909.         inside = TRUE;
  910.       }
  911.     else
  912.       {
  913.         inside = FALSE;
  914.       }
  915.     *argvptr = argptr;
  916.  
  917.     while (*argptr)
  918.       {
  919.         if (*argptr == '\"'  &&  inside)
  920.           {
  921.         char *ptr;
  922.         char *oldptr;
  923.  
  924.         /**
  925.         ***  Found a "", remove the second ".
  926.         **/
  927.         for(ptr = argptr++, oldptr = *argvptr;
  928.             ptr >= oldptr;  --ptr)
  929.           {
  930.             *(ptr+1) = *ptr;
  931.           }
  932.         *argvptr = oldptr+1;
  933.           }
  934.         ++argptr;
  935.       }
  936.     ++argptr;
  937.       }
  938.     *argvptr = NULL;
  939.  
  940.     return(argv);
  941.   }
  942.  
  943.  
  944.  
  945.  
  946.  
  947. /**
  948. ***  Finally main().
  949. **/
  950. int main(int argc, char *argv[])
  951.  
  952.   {
  953.     char *cflags;
  954.  
  955.     NewList(&OptionList);
  956.  
  957.     if ((cflags = getenv("CCOPT")))
  958.       {
  959.     int envargc;
  960.     char **envargv;
  961.  
  962.     if (!(envargv = SplitArgs(cflags, &envargc)))
  963.       {
  964.         fprintf(stderr, "Out of memory!\n");
  965.         exit(20);
  966.       }
  967.     ParseArgs(envargc, envargv);
  968.       }
  969.  
  970.     ParseArgs(argc-1, argv+1);
  971.  
  972.     switch(CompatibilityMode)
  973.       {
  974.     case COMPATIBILITYMODE_GCC:
  975.       CompileGcc();
  976.       break;
  977.     case COMPATIBILITYMODE_SAS:
  978.       CompileSAS();
  979.       break;
  980.     case COMPATIBILITYMODE_DICE:
  981.       CompileDice();
  982.       break;
  983.       }
  984.   }
  985.